package com.lry.sign;

import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.pdf.*;
import com.itextpdf.signatures.*;

import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
import java.util.Calendar;

/**
 * @author Ethan
 * @version 1.0
 * @description: 链融易电子签章，分离式哈希签名
 *
 * @date 2021/6/24 0024
 */
public class DeferredSignPdfAssLry{
    private byte[] toSignHash;//待签名哈希
    private String hashAlgorithm = DigestAlgorithms.SHA256;//摘要算法，可修改
    //默认使用分离式签名，可修改
    private PdfName dicFilter = PdfName.Adobe_PPKLite;
    private PdfName dicSubfilter = PdfName.Adbe_pkcs7_detached;

    /**
     * 1.initSigner初始化签名对象；
     * 2.通过externalSignatureContainer获取digestHash，去cfca计算签名值；
     * 3.embedSignature，嵌入签名值。embedSignature可以独立和上面的步骤分离
     * @param pdfFile 源文件字节码
     * @param outPath 签名文件
     * @param externalSignatureContainer 签章实现
     * @return
     * @throws IOException
     */
    public DeferredSignPdfAssLry initSigner(byte[] pdfFile, String outPath,SignInfo signInfo,IExternalSignatureContainer externalSignatureContainer) throws IOException, GeneralSecurityException {
        boolean success = false;
        int estimatedSize = 8192;//300000;
        while (!success) {
            try {
                PdfReader pdfReader = new PdfReader(new ByteArrayInputStream(pdfFile));
                OutputStream output = new FileOutputStream(outPath);
                StampingProperties stampingProperties = new StampingProperties();
                if (signInfo.isAppendModel() == true) {
                    stampingProperties.useAppendMode();
                }
                PdfSigner signer = new PdfSigner(pdfReader, output, stampingProperties);
                PdfSignatureAppearance appearance = signer.getSignatureAppearance();
                appearance
                        .setPageRect(signInfo.getRectangle())
                        .setPageNumber(signInfo.getPageNumber())
                        .setSignatureGraphic(ImageDataFactory.create(signInfo.getImgPath()))
                        .setReason(signInfo.getReason())
                        .setLocation(signInfo.getLocation())
                        .setRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC);
              /*  appearance.setLayer2Text("This document was signed by Bruno Specimen");
                appearance.setImage(ImageDataFactory.create(signInfo.getImgPath()));
                appearance.setImageScale(-1);*/
                signer.setFieldName(signInfo.getFieldName());
                signer.setSignDate(Calendar.getInstance());
                signer.signExternalContainer(externalSignatureContainer, estimatedSize);
                success = true;
            } catch (IOException e) {
                e.printStackTrace();
                estimatedSize += 1000;
            } catch (GeneralSecurityException e) {
                e.printStackTrace();
            }
        }
        return this;
    }

    /**
     * 嵌入分离式签名信息
     * @param readPath 已经进行空签章的文件
     * @param outPath 输出文件
     * @param fieldName 已经打入的签章字段名，必须和空签章打入的一致
     * @param external 签名
     * @throws IOException
     * @throws GeneralSecurityException
     */
    public static void embedSignature(String readPath, String outPath, String fieldName, IExternalSignatureContainer external) throws IOException, GeneralSecurityException {
        try( PdfReader reader = new PdfReader(readPath);FileOutputStream os = new FileOutputStream(outPath)) {
            PdfSigner signer = new PdfSigner(reader, os, new StampingProperties());
            try {
                // Signs a PDF where space was already reserved. The field must cover the whole document.
                signer.signDeferred(signer.getDocument(), fieldName, os, external);
            } catch (IOException e) {
                throw new IOException("embedSignature signing exception",e);
            } catch (GeneralSecurityException e) {
                throw new GeneralSecurityException("embedSignature signing exception",e);
            }
        }
    }

    public byte[] getToSignHash() {
        return toSignHash;
    }



    public String getHashAlgorithm() {
        return this.hashAlgorithm;
    }

    public void setHashAlgorithm(String hashAlgorithm) {
        this.hashAlgorithm = hashAlgorithm;
    }

    public PdfName getDicFilter() {
        return this.dicFilter;
    }

    public void setDicFilter(PdfName dicFilter) {
        this.dicFilter = dicFilter;
    }

    public PdfName getDicSubfilter() {
        return this.dicSubfilter;
    }

    public void setDicSubfilter(PdfName dicSubfilter) {
        this.dicSubfilter = dicSubfilter;
    }
}
